using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.UI;

namespace JH
{
    /// <summary>
    ///  鼠标悬停在折线图上的组件
    /// </summary>
    public class LineChartMouseHover : BasicGraphicRender<Vector2>, IPointerEnterHandler, IPointerExitHandler
    {
        /// <summary>
        ///  是否鼠标进入了图表区域
        /// </summary>
        private bool _isEnter;

        /// <summary>
        ///  采样容差
        /// </summary>
        [SerializeField] private float sampleTolerance = 0.02f;

        /// <summary>
        ///  全部的采样组件
        /// </summary>
        private IMouseHoverSample[] _samples;

        /// <summary>
        ///  获取全部的采样组件
        /// </summary>
        private IMouseHoverSample[] Samples => _samples ??= this.GetChartComps<IMouseHoverSample, Vector2>(true);

        /// <summary>
        /// 曲线的渲染器
        /// </summary>
        [SerializeField] [HideInInspector] private Vector2LineRender lineRender;

        /// <summary>
        ///  边界处理器
        /// </summary>
        [SerializeField] [HideInInspector] private BoundaryHandler boundaryHandler;

        private void Update()
        {
            if (lineRender == null || boundaryHandler == null)
                return;

            if (!_isEnter) return;

            // 获取鼠标位置，使用新输入系统
            Vector2 mousePosition = Mouse.current.position.ReadValue();

            // 把鼠标坐标转换为UV坐标
            var uv = boundaryHandler.GetUVByScreenPosition(mousePosition);
            // 采样曲线，获取采样点
            var samplePoint = Sample(uv);
            if (samplePoint == null)
            {
                OnPointerExit(null);
                return;
            }

            // 告知所有采样组件，当前采样点
            for (int i = 0; i < Samples.Length; i++)
            {
                Samples[i].OnSample(samplePoint.Value);
            }
        }

        /// <summary>
        ///  采样曲线，获取采样点
        /// </summary>
        /// <param name="uv">采样时用的UV</param>
        private LineVertexInfo? Sample(Vector2 uv)
        {
            // 如果没有线渲染器，或者没有顶点列表，或者顶点数量小于2，直接返回空
            if (lineRender == null || lineRender.NoWidthVertexList == null || lineRender.NoWidthVertexList.Count < 2)
            {
                return null;
            }

            // 从左到右逐个遍历数据点
            for (var i = 0; i < lineRender.NoWidthVertexList.Count; i++)
            {
                // 当前数据点
                var current = lineRender.NoWidthVertexList[i];

                // 如果当前数据点和采样点的UV.x在容差内，则认为当前点就是目标点
                if (Mathf.Abs(current.UV.x - uv.x) < sampleTolerance)
                    return current;

                //如果当前数据点的UV.x大于采样的UV.x，说明找到了右侧的点
                if (current.UV.x > uv.x)
                {
                    //如果有左侧点
                    if (i > 0)
                    {
                        var left = lineRender.NoWidthVertexList[i - 1];

                        // 线性插值计算
                        return Lerp(left, current, (uv.x - left.UV.x) / (current.UV.x - left.UV.x));
                    }

                    // 如果没有左侧点，直接返回当前点
                    return current;
                }
            }

            //如果遍历完毕都没有找到合适的点，返回最后一个点
            return lineRender.NoWidthVertexList.Last();
        }

        /// <summary>
        ///  对两个顶点进行线性插值
        /// </summary>
        private LineVertexInfo Lerp(LineVertexInfo a, LineVertexInfo b, float t)
        {
            // 插值计算
            return new LineVertexInfo
            {
                BoundaryHandler = a.BoundaryHandler,
                OriginPoint = Vector2.Lerp(a.OriginPoint, b.OriginPoint, t),
                Color = Color.Lerp(a.Color, b.Color, t),
                LeftDir = a.LeftDir.HasValue && b.LeftDir.HasValue
                    ? Vector2.Lerp(a.LeftDir.Value, b.LeftDir.Value, t)
                    : null,
                RightDir = a.RightDir.HasValue && b.RightDir.HasValue
                    ? Vector2.Lerp(a.RightDir.Value, b.RightDir.Value, t)
                    : null
            };
        }

        protected override void OnPopulateMesh(VertexHelper vh)
        {
            vh.Clear();
        }

        /// <summary>
        ///  鼠标进入时
        /// </summary>
        public void OnPointerEnter(PointerEventData eventData)
        {
            if (_isEnter) return;
            _isEnter = true;
            for (int i = 0; i < Samples.Length; i++)
            {
                Samples[i].OnHoverStateChanged(true);
            }
        }

        /// <summary>
        ///  鼠标离开时
        /// </summary>
        public void OnPointerExit(PointerEventData eventData)
        {
            if (!_isEnter) return;
            _isEnter = false;
            for (int i = 0; i < Samples.Length; i++)
            {
                Samples[i].OnHoverStateChanged(false);
            }
        }

#if UNITY_EDITOR
        protected override void OnValidate()
        {
            base.OnValidate();
            color = Color.clear;
            Priority = 1;
            _samples = null;
            lineRender = this.GetChart<Vector2>().GetChartComp<Vector2LineRender, Vector2>();
            boundaryHandler = this.GetChart<Vector2>().GetChartComp<BoundaryHandler, Vector2>();
        }
#endif
    }
}